/**************************************************************************
 *                                                                        *
 *         Copyright (c) 2014 by Generalplus Inc.                         *
 *                                                                        *
 *  This software is copyrighted by and is the property of Generalplus    *
 *  Inc. All rights are reserved by Generalplus Inc.                      *
 *  This software may only be used in accordance with the                 *
 *  corresponding license agreement. Any unauthorized use, duplication,   *
 *  distribution, or disclosure of this software is expressly forbidden.  *
 *                                                                        *
 *  This Copyright notice MUST not be removed or modified without prior   *
 *  written consent of Generalplus Technology Co., Ltd.                   *
 *                                                                        *
 *  Generalplus Inc. reserves the right to modify this software           *
 *  without notice.                                                       *
 *                                                                        *
 *  Generalplus Inc.                                                      *
 *  No.19, Industry E. Rd. IV, Hsinchu Science Park                       *
 *  Hsinchu City 30078, Taiwan, R.O.C.                                    *
 *                                                                        *
 **************************************************************************/
/********************************************************************
* Purpose:  GPIO driver/interface
* Author:
* Date:		2014/07/15
* Copyright Generalplus Corp. ALL RIGHTS RESERVED.
* Version : 1.00
* History :
*********************************************************************/
/******************************************************************************
 * Paresent Header Include
 ******************************************************************************/
#include "drv_l1_sfr.h"
#include "drv_l1_gpio.h"

//=== This is for code configuration DON'T REMOVE or MODIFY it ===//
#if (defined _DRV_L1_GPIO) && (_DRV_L1_GPIO == 1)	//

//================================================================//
/******************************************************************************
 * Static Variables
 ******************************************************************************/
/******************************************************************************
 * Function Prototypes
 ******************************************************************************/
BOOLEAN gpio_init_io(INT32U port, BOOLEAN direction);
BOOLEAN gpio_read_io(INT32U port);
BOOLEAN gpio_write_io(INT32U port, BOOLEAN data);
BOOLEAN gpio_set_port_attribute(INT32U port, BOOLEAN attribute);
BOOLEAN gpio_write_all_by_set(GPIO_SET_ENUM gpio_set_num, INT32U write_data);
BOOLEAN gpio_get_dir(INT32U port);
INT32U	gpio_read_all_by_set(GPIO_SET_ENUM gpio_set_num);
BOOLEAN gpio_drving_init_io(GPIO_ENUM port, IO_DRV_LEVEL gpio_driving_level);
void	gpio_drving_uninit(void);
void	gpio_basic_init(void);

/******************************************************************************
 * Function Body
 ******************************************************************************/
/* This interface is for the application layer to initail the GPIO direction*/
/* init_io will not only modyfy the direction but also control the attribute value */

/*
Function Name	gpio_init_io
Description	General IO setting
Header File	drv_l1_gpio.h
Syntax	BOOLEAN gpio_init_io(INT32U port, BOOLEAN direction)
Parameters	port: IO pin number(ex. IOA [0] is 0, IOB[0] is 16 and IOC[3] is 35.)
			direction: Value filled in direction and attribute bit, 1: set as 1, 0: set as 1
Return Values	1: Success
			0: Failed. The assigned port is not existed.
*/
BOOLEAN gpio_init_io(INT32U port, BOOLEAN direction)
{
	INT16U	gpio_set;
	INT16U	gpio_set_num;

	gpio_set = port / EACH_REGISTER_GPIO_NUMS;
	gpio_set_num = port % EACH_REGISTER_GPIO_NUMS;

	if(direction == GPIO_OUTPUT)
	{
		DRV_Reg32(IOA_ATTRIB_ADDR + (EACH_DIR_REG_OFFSET * gpio_set)) |= (1 << gpio_set_num);	/*Set attribute to 0 for input */
		DRV_Reg32((IOA_DIR_ADDR + EACH_DIR_REG_OFFSET * gpio_set)) |= (1 << gpio_set_num);
	}
	else
	if(direction == GPIO_INPUT)
	{
		DRV_Reg32(IOA_ATTRIB_ADDR + (EACH_DIR_REG_OFFSET * gpio_set)) &= ~(1 << gpio_set_num);	/*Set attribute to 1 for output */
		DRV_Reg32((IOA_DIR_ADDR + EACH_DIR_REG_OFFSET * gpio_set)) &= ~(1 << gpio_set_num);
	}
	else
	if(direction == GPIO_FLOAT)
	{
		DRV_Reg32(IOA_ATTRIB_ADDR + (EACH_DIR_REG_OFFSET * gpio_set)) |= (1 << gpio_set_num);
		DRV_Reg32((IOA_DIR_ADDR + EACH_DIR_REG_OFFSET * gpio_set)) &= ~(1 << gpio_set_num);
	}
	else
	{
		return GPIO_FAIL;
	}

	return GPIO_OK;
}

/*
Function Name	gpio_read_io
Description	Read IO port data
Header File	drv_l1_gpio.h
Syntax	BOOLEAN gpio_read_io(INT32U port)
Parameters	port: IO number(ex. IOA [0] is 0, IOB[0] is 16 and IOC[3] is 35.)
Return Values	Input status of the whole IO port which contains this IO
*/
BOOLEAN gpio_read_io(INT32U port)
{
	INT16U	gpio_set;
	INT16U	gpio_set_num;

	gpio_set = port / EACH_REGISTER_GPIO_NUMS;
	gpio_set_num = port % EACH_REGISTER_GPIO_NUMS;
	return((DRV_Reg32(IOA_DATA_ADDR + EACH_GPIO_DATA_REG_OFFSET * gpio_set) >> gpio_set_num) & LOWEST_BIT_MASK);
}

/*
Function Name	gpio_write_io
Description	Set IO port output data
Header File	drv_l1_gpio.h
Syntax	BOOLEAN gpio_write_io(INT32U port, BOOLEAN data)
Parameters	port: IO number(ex. IOA [0] is 0, IOB[0] is 16 and IOC[3] is 35.)
			data: 1: output high, 0: output low
			Output status of whole IO port which contains this IO
Return Values	1: Success
			0: Failed
*/
BOOLEAN gpio_write_io(INT32U port, BOOLEAN data)
{
	INT16U	gpio_set;
	INT16U	gpio_set_num;
	gpio_set = port / EACH_REGISTER_GPIO_NUMS;		// gpio_set_array
	gpio_set_num = port % EACH_REGISTER_GPIO_NUMS;	// gpio_setbit_array
	data &= LOWEST_BIT_MASK;
	if(data == DATA_HIGH)
	{
		DRV_Reg32((IOA_BUFFER_ADDR + EACH_GPIO_DATA_REG_OFFSET * gpio_set)) |= (1 << gpio_set_num);
	}
	else
	if(data == DATA_LOW)
	{
		DRV_Reg32((IOA_BUFFER_ADDR + EACH_GPIO_DATA_REG_OFFSET * gpio_set)) &= ~(1 << gpio_set_num);
	}
	else
	{
		return GPIO_FAIL;
	}

	return GPIO_OK;
}

/*
Function Name	gpio_drving_init_io
Description	Set GPIO driving capability
Header File	drv_l1_gpio.h
Syntax	BOOLEAN gpio_drving_init_io(GPIO_ENUM port, IO_DRV_LEVEL gpio_driving_level)
Parameters	port: IO pin number(ex. IOA [0] is 0, IOB[0] is 16 and IOC[3] is 35.)
			gpio_driving_level: IO drivering capability
Return Values	1: Success
			0: Failed
*/
BOOLEAN gpio_drving_init_io(GPIO_ENUM port, IO_DRV_LEVEL gpio_driving_level)
{
	INT16U	gpio_set;
	INT16U	gpio_set_num;
	INT32U	drv_level;

	gpio_set = port / EACH_REGISTER_GPIO_NUMS;
	gpio_set_num = port % EACH_REGISTER_GPIO_NUMS;
	drv_level = (INT32U) gpio_driving_level;

	if(port < IO_E8)	// IOA/B/C/D and E(8-bit)
	{
		if(drv_level == 0)
		{
			DRV_Reg32(IOA_DRV + (EACH_DIR_REG_OFFSET * gpio_set)) &= ~(1 << gpio_set_num);
		}
		else			//if (drv_level == 1)
		{
			DRV_Reg32(IOA_DRV + (EACH_DIR_REG_OFFSET * gpio_set)) |= (1 << gpio_set_num);
		}
	}
	else
	{
		return GPIO_FAIL;
	}

	return GPIO_OK;
}

/*
Function Name	gpio_drving_uninit
Description	Set GPIO driving capability to the lowest level
Header File	drv_l1_gpio.h
Syntax	void gpio_drving_uninit(void)
Parameters	None
Return Values	None
*/
void gpio_drving_uninit(void)
{
	R_IOA_DRV = 0;
	R_IOB_DRV = 0;
	R_IOC_DRV = 0;
	R_IOD_DRV = 0;
	R_IOE_DRV = 0;
}

/*
Function Name	gpio_set_port_attribute
Description	Set IO port attribute
Header File	drv_l1_gpio.h
Syntax	BOOLEAN gpio_set_port_attribute(INT32U port, BOOLEAN attribute)
Parameters	port: IO number(ex. IOA [0] is 0, IOB[0] is 16 and IOC[3] is 35.)
			attribute: 1: set as 1, 0: set as 0
Return Values	1: Success
			0: Failed
*/
BOOLEAN gpio_set_port_attribute(INT32U port, BOOLEAN attribute)
{
	INT16U	gpio_set;
	INT16U	gpio_set_num;

	gpio_set = port / EACH_REGISTER_GPIO_NUMS;
	gpio_set_num = port % EACH_REGISTER_GPIO_NUMS;
	attribute &= LOWEST_BIT_MASK;
	if(attribute == ATTRIBUTE_HIGH)
	{
		DRV_Reg32((IOA_ATTRIB_ADDR + EACH_ATTRIB_REG_OFFSET * gpio_set)) |= (1 << gpio_set_num);
	}
	else
	if(attribute == ATTRIBUTE_LOW)
	{
		DRV_Reg32((IOA_ATTRIB_ADDR + EACH_ATTRIB_REG_OFFSET * gpio_set)) &= ~(1 << gpio_set_num);
	}
	else
	{
		return GPIO_FAIL;
	}

	return GPIO_OK;
}

/*INPUT :
         gpio_set_num: GPIO_SET_A, GPIO_SET_B, GPIO_SET_C, GPIO_SET_D
         write_data: 0x00001234h
*/

/*
Function Name	gpio_write_all_by_set
Description	Set IO port output value
Header File	drv_l1_gpio.h
Syntax	BOOLEAN gpio_write_all_by_set(INT32U gpio_set_num, INT32U write_data)
Parameters	gpio_set_num: IO number(ex. IOA [0] is 0, IOB[0] is 16 and IOC[3] is 35.)
			write_data: 1: output high, 0: output low
			Output status of whole IO port which contains this IO
Return Values	1: Success
			0: Failed
*/
BOOLEAN gpio_write_all_by_set(GPIO_SET_ENUM gpio_set_num, INT32U write_data)
{
	if(gpio_set_num < GPIO_SET_MAX)
	{
		DRV_WriteReg32(IOA_BUFFER_ADDR + EACH_GPIO_DATA_REG_OFFSET * gpio_set_num, (write_data & LOWEST_BIT_MASK));
		return GPIO_OK;
	}
	else
	{
		return GPIO_FAIL;
	}
}

/*
Function Name	gpio_read_all_by_set
Description	Read IO port data
Header File	drv_l1_gpio.h
Syntax	INT32U gpio_read_all_by_set(INT8U gpio_set_num)
Parameters	gpio_set_num: IO number(ex. IOA [0] is 0, IOB[0] is 16 and IOC[3] is 35.)
Return Values	Not 0xFFFFFFFF: Input status of this IO
			0xFFFFFFFF: gpio_set_num is out of range
*/
INT32U gpio_read_all_by_set(GPIO_SET_ENUM gpio_set_num)
{
	if(gpio_set_num < GPIO_SET_MAX)
	{
		return DRV_Reg32(IOA_DATA_ADDR + EACH_GPIO_DATA_REG_OFFSET * gpio_set_num);
	}

	return 0xFFFFFFFF;
}

/*
Function Name	gpio_get_dir
Description	Get IO port direction
Header File	drv_l1_gpio.h
Syntax	BOOLEAN gpio_get_dir(INT32U port)
Parameters	port: IO number(ex. IOA [0] is 0, IOB[0] is 16 and IOC[3] is 35.)
Return Values	Direction setting of the specified IO
*/
BOOLEAN gpio_get_dir(INT32U port)
{
	INT16U	gpio_set;
	INT16U	gpio_set_num;

	gpio_set = port / EACH_REGISTER_GPIO_NUMS;
	gpio_set_num = port % EACH_REGISTER_GPIO_NUMS;

	return((DRV_Reg32(IOA_DIR_ADDR + EACH_DIR_REG_OFFSET * gpio_set) >> gpio_set_num) & LOWEST_BIT_MASK);
}

/*
Function Name	gpio_set_ice_en
Description	Set IOH[5:2] as JTAG pins or GPIOs
Header File	drv_l1_gpio.h
Syntax	void gpio_set_ice_en(BOOLEAN status)
Parameters	status: 1: BKUEB, 0: GPIOs
Return Values	None
*/
void gpio_set_ice_en(BOOLEAN status)
{
	if(status == TRUE)
	{
		R_GPIOCTRL |= 1;	/* enable */
	}
	else
	{
		R_GPIOCTRL &= ~1;	/* disable */
	}
}

#if 0
static BOOLEAN gpio_get_attrib(INT32U port)
{
	INT16U	gpio_set;
	INT16U	gpio_set_num;

	gpio_set = port / EACH_REGISTER_GPIO_NUMS;
	gpio_set_num = port % EACH_REGISTER_GPIO_NUMS;

	return((DRV_Reg32(IOA_ATTRIB_ADDR + EACH_ATTRIB_REG_OFFSET * gpio_set) >> gpio_set_num) & LOWEST_BIT_MASK);
}

#endif

//=== This is for code configuration DON'T REMOVE or MODIFY it ===//
#endif //(defined _DRV_L1_GPIO) && (_DRV_L1_GPIO == 1)            //

//================================================================//
